#include "atomtimer.h"
#include "atom.h"
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <signal.h>
#include <syslog.h>


static int msleep(long msec)
{
    struct timespec ts;
    int res;

    if (msec < 0)
    {
        errno = EINVAL;
        return -1;
    }

    ts.tv_sec = msec / 1000;
    ts.tv_nsec = (msec % 1000) * 1000000;

    do {
        res = nanosleep(&ts, &ts);
    } while (res && errno == EINTR);

    return res;
}

uint8_t atomTimerDelay(uint32_t ticks)
{

    int result = msleep( ticks * 1000 / SYSTEM_TICKS_PER_SEC);

    if (result == 0) {
        return ATOM_OK;
    }

	return ATOM_ERR_TIMER;
}

void timer_handler(int sig, siginfo_t* si, void* uc)
{
    ATOM_TIMER* timer = (ATOM_TIMER*)(si->si_value.sival_ptr);
    if (timer->cb_func != NULL) {
        timer->cb_func(timer->cb_data);
    }
    timer->cb_ticks = 0; // reset tick count
}

uint8_t atomTimerRegister(ATOM_TIMER* timer_ptr)
{
    struct sigevent sev;
    struct itimerspec its;
    struct sigaction sa;

    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = timer_handler;
    sigemptyset(&sa.sa_mask);
    sigaction(SIGRTMIN, &sa, NULL);

    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_signo = SIGRTMIN;
    sev.sigev_value.sival_ptr = timer_ptr;
    timer_create(CLOCK_REALTIME, &sev, &(timer_ptr->timerid));

    // Set initial and interval time for timer
    long tick_ns = (1000000000 / SYSTEM_TICKS_PER_SEC);
    long sec = timer_ptr->cb_ticks / SYSTEM_TICKS_PER_SEC;
    long nsec = (timer_ptr->cb_ticks % SYSTEM_TICKS_PER_SEC) * tick_ns;

    its.it_interval.tv_sec = sec;  // Interval time in seconds
    its.it_interval.tv_nsec = nsec;
    its.it_value = its.it_interval;

    // Start the timer
    timer_settime(&(timer_ptr->timerid), 0, &its, NULL);

    return ATOM_OK;
}

uint8_t atomTimerCancel(ATOM_TIMER* timer_ptr)
{
    timer_delete(timer_ptr->timerid);
    timer_ptr->cb_func = NULL;
    timer_ptr->cb_data = NULL;
    timer_ptr->cb_ticks = 0;

    return ATOM_OK;
}

uint32_t atomTimeGet(void)
{
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000) / SYSTEM_TICKS_PER_SEC;
}

void atomTimeSet(uint32_t new_time)
{
    SYSLOG(LOG_NOTICE, "atomTimeSet not implemented under vos!");
}

uint32_t atomUserTimerWakeupTimeGet(void)
{
    SYSLOG(LOG_NOTICE, "atomUserTimerWakeupTimeGet not implemented under vos!");
    return (ATOM_ERROR);
}

void atomUserTimerUpdate(uint32_t sleep_time)
{
    SYSLOG(LOG_NOTICE, "atomUserTimerUpdate not implemented under vos!");
}